Named Routes in Flutter
Named Routes in Flutter provide a way to navigate between screens using unique string-based route names such as /home, /login, /profile, and /settings. Instead of creating a MaterialPageRoute every time, routes can be registered centrally in MaterialApp and opened using Navigator.pushNamed().
Important: Flutter's current documentation states that named routes are no longer recommended for most new applications. For simple navigation, Navigator with MaterialPageRoute can be used, while applications with more advanced routing and deep-linking requirements can use go_router or another routing solution. Named routes are still useful for learning navigation and understanding existing Flutter applications.
1. What Are Named Routes?
A named route is a screen associated with a unique string identifier. For example:
/ → Home screen
/login → Login screen
/profile → Profile screen
/settings → Settings screen
/about → About screen
Instead of writing a complete route every time, you can simply write:
Navigator.pushNamed(context, '/profile');
The route name is looked up in the application's routing table and the corresponding screen is created.
2. Why Use Named Routes?
- Centralizes route definitions.
- Makes navigation code shorter.
- Provides consistent route names throughout an application.
- Can be useful when many parts of an application navigate to the same screen.
- Can pass arguments to screens.
- Supports route replacement and route-stack operations.
- Helps developers understand routing in existing Flutter projects.
3. Named Routes and Navigator
Flutter's Navigator manages a stack of routes. A route can be pushed onto the stack when opening a new screen and popped when closing the current screen.
Home
↓ pushNamed('/profile')
Profile
↓ pop()
Home
Navigator.pushNamed() pushes a named route onto the Navigator stack, while Navigator.pop() removes the current route.
4. Basic Named Route Syntax
Navigator.pushNamed(context, '/profile');
The first parameter is the current BuildContext, and the second parameter is the registered route name.
5. Creating Named Routes with MaterialApp
Named routes are commonly defined using the routes property of MaterialApp.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => const HomeScreen(),
'/profile': (context) => const ProfileScreen(),
'/settings': (context) => const SettingsScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/profile');
},
child: const Text('Open Profile'),
),
),
);
}
}
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Profile'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go Back'),
),
),
);
}
}
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Settings'),
),
body: const Center(
child: Text('Settings Screen'),
),
);
}
}
6. Understanding the routes Property
The routes property accepts a map where the key is the route name and the value is a widget builder.
routes: {
'/': (context) => const HomeScreen(),
'/profile': (context) => const ProfileScreen(),
'/settings': (context) => const SettingsScreen(),
}
Conceptually:
| Route Name | Screen |
/ | HomeScreen |
/profile | ProfileScreen |
/settings | SettingsScreen |
7. initialRoute
The initialRoute property determines which named route should be displayed when the application starts.
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const HomeScreen(),
'/login': (context) => const LoginScreen(),
'/profile': (context) => const ProfileScreen(),
},
);
In this example, the application starts with the / route.
8. Navigating to Another Screen
Use Navigator.pushNamed() to open a registered named route.
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/profile');
},
child: const Text('Open Profile'),
)
The Navigator searches for the /profile route and opens the corresponding screen.
9. Closing a Named Route
A named route can be closed using Navigator.pop().
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Back'),
)
The current route is removed from the Navigator stack and the previous route becomes visible.
10. Navigating Between Multiple Named Routes
Consider an application containing Home, Products, Cart, and Profile screens.
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const HomeScreen(),
'/products': (context) => const ProductsScreen(),
'/cart': (context) => const CartScreen(),
'/profile': (context) => const ProfileScreen(),
},
);
Navigation can then be performed from different screens:
Navigator.pushNamed(context, '/products');
Navigator.pushNamed(context, '/cart');
Navigator.pushNamed(context, '/profile');
11. Complete Multi-Screen Example
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => const HomeScreen(),
'/about': (context) => const AboutScreen(),
'/contact': (context) => const ContactScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/about');
},
child: const Text('About'),
),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/contact');
},
child: const Text('Contact'),
),
],
),
);
}
}
class AboutScreen extends StatelessWidget {
const AboutScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('About')),
body: const Center(
child: Text('About Screen'),
),
);
}
}
class ContactScreen extends StatelessWidget {
const ContactScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Contact')),
body: const Center(
child: Text('Contact Screen'),
),
);
}
}
12. Named Route Constants
Writing route names as strings throughout a large project can cause spelling mistakes. A common approach is to store route names in constants.
class AppRoutes {
static const String home = '/';
static const String login = '/login';
static const String profile = '/profile';
static const String settings = '/settings';
}
Register the routes:
MaterialApp(
routes: {
AppRoutes.home: (context) => const HomeScreen(),
AppRoutes.login: (context) => const LoginScreen(),
AppRoutes.profile: (context) => const ProfileScreen(),
AppRoutes.settings: (context) => const SettingsScreen(),
},
);
Navigate using the constants:
Navigator.pushNamed(context, AppRoutes.profile);
This reduces the chance of accidentally typing different route names in different parts of the application.
13. Passing Arguments to Named Routes
Navigator.pushNamed() supports an optional arguments parameter. This allows data to be passed to the destination route.
Navigator.pushNamed(
context,
'/profile',
arguments: {
'name': 'Rahul',
'age': 25,
},
);
The arguments are associated with the route through RouteSettings.arguments.
14. Reading Arguments with ModalRoute
The destination screen can access arguments using ModalRoute.of(context).
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
final arguments =
ModalRoute.of(context)!.settings.arguments as Map;
final String name = arguments['name'];
final int age = arguments['age'];
return Scaffold(
appBar: AppBar(
title: const Text('Profile'),
),
body: Center(
child: Text(
'Name: $name\nAge: $age',
textAlign: TextAlign.center,
),
),
);
}
}
15. Passing a Custom Object
Instead of passing a Map, you can pass a custom Dart object.
class User {
final String name;
final String email;
User({
required this.name,
required this.email,
});
}
Pass the object:
final user = User(
name: 'Amit',
email: '[email protected]',
);
Navigator.pushNamed(
context,
'/profile',
arguments: user,
);
Read it on the destination screen:
final user = ModalRoute.of(context)!.settings.arguments as User;
Text(user.name);
Text(user.email);
16. Passing Arguments Using onGenerateRoute
onGenerateRoute provides more control over how routes are created and is useful when route creation depends on arguments or route names.
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == '/profile') {
final user = settings.arguments as User;
return MaterialPageRoute(
builder: (context) {
return ProfileScreen(user: user);
},
);
}
return MaterialPageRoute(
builder: (context) => const HomeScreen(),
);
},
);
Navigation:
Navigator.pushNamed(
context,
'/profile',
arguments: User(
name: 'Amit',
email: '[email protected]',
),
);
17. What is onGenerateRoute?
onGenerateRoute is a callback used to create routes dynamically when a route is requested. It receives RouteSettings, which contains information such as the requested route name and arguments.
onGenerateRoute: (settings) {
print(settings.name);
print(settings.arguments);
return MaterialPageRoute(
builder: (context) => const HomeScreen(),
);
}
It can be useful when an application has many routes or needs custom route-generation logic.
18. Handling Unknown Routes
You can provide onUnknownRoute to display a fallback screen when a requested route cannot be resolved.
MaterialApp(
routes: {
'/': (context) => const HomeScreen(),
'/profile': (context) => const ProfileScreen(),
},
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (context) => const NotFoundScreen(),
);
},
);
For example, if the application tries to navigate to an unavailable route:
Navigator.pushNamed(context, '/something-that-does-not-exist');
The application can display the NotFoundScreen instead of leaving the user without an appropriate destination.
19. pushReplacementNamed()
pushReplacementNamed() replaces the current route with another named route.
This is particularly useful after login or registration.
Navigator.pushReplacementNamed(
context,
'/dashboard',
);
Example login flow:
ElevatedButton(
onPressed: () {
Navigator.pushReplacementNamed(
context,
'/dashboard',
);
},
child: const Text('Login'),
)
After reaching the dashboard, pressing the back button does not return to the login screen because the login route was replaced.
20. pushNamedAndRemoveUntil()
This method pushes a named route and removes previous routes according to a predicate.
A common example is logging out and returning to the login screen while removing previous application screens.
Navigator.pushNamedAndRemoveUntil(
context,
'/login',
(route) => false,
);
This clears the existing Navigator stack and leaves the login route as the active route.
21. popAndPushNamed()
popAndPushNamed() removes the current route and pushes another named route.
Navigator.popAndPushNamed(
context,
'/settings',
);
This can be useful when the current screen should be replaced by another screen in a single navigation operation.
22. Named Routes with Login and Dashboard
A typical application can define login and dashboard routes like this:
MaterialApp(
initialRoute: '/login',
routes: {
'/login': (context) => const LoginScreen(),
'/dashboard': (context) => const DashboardScreen(),
'/profile': (context) => const ProfileScreen(),
},
);
After successful authentication:
Navigator.pushReplacementNamed(
context,
'/dashboard',
);
From the dashboard:
Navigator.pushNamed(
context,
'/profile',
);
23. Named Routes in an E-Commerce App
Imagine an e-commerce application with these routes:
| Route | Purpose |
/ | Home |
/products | Product list |
/product-details | Product details |
/cart | Shopping cart |
/checkout | Checkout |
/order-success | Order confirmation |
The route table might look like:
routes: {
'/': (context) => const HomeScreen(),
'/products': (context) => const ProductsScreen(),
'/product-details': (context) => const ProductDetailsScreen(),
'/cart': (context) => const CartScreen(),
'/checkout': (context) => const CheckoutScreen(),
'/order-success': (context) => const OrderSuccessScreen(),
}
Opening the cart:
Navigator.pushNamed(context, '/cart');
Opening checkout:
Navigator.pushNamed(context, '/checkout');
After successful payment:
Navigator.pushNamedAndRemoveUntil(
context,
'/order-success',
(route) => false,
);
24. Named Routes vs Direct Navigator.push()
| Feature | Named Routes | Direct Route |
| Navigation | pushNamed() | push() |
| Route identifier | String name | Route object |
| Central route table | Usually used | Not required |
| Arguments | Supported | Supported directly through constructors |
| Simple navigation | Works | Works |
| Large/complex routing | Limited | Can become manual |
Direct navigation example:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
Named route example:
Navigator.pushNamed(
context,
'/profile',
);
25. Important Current Flutter Recommendation
Flutter's current navigation documentation does not recommend named routes for most new applications. Named routes have limitations, especially for advanced deep linking and browser history behavior. For simple applications, Navigator with MaterialPageRoute is an option. For applications requiring advanced routing, deep linking, or more sophisticated navigation configuration, Flutter recommends using a routing solution such as go_router.
However, named routes remain important for learning Flutter navigation and for maintaining or understanding applications that already use them.
26. Named Routes and Deep Linking
A deep link is a URL or external link that opens a specific location inside an application. Flutter supports deep linking on Android, iOS, and the web.
Named routes can be used for basic route-based navigation, but they have limitations for advanced deep-link behavior. For modern applications with complex deep linking, a Router-based solution or routing package such as go_router is generally more appropriate.
27. Named Routes with Bottom Navigation
Named routes can also be triggered from navigation controls.
NavigationBar(
selectedIndex: 0,
onDestinationSelected: (index) {
if (index == 0) {
Navigator.pushNamed(context, '/home');
} else if (index == 1) {
Navigator.pushNamed(context, '/profile');
} else if (index == 2) {
Navigator.pushNamed(context, '/settings');
}
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.home),
label: 'Home',
),
NavigationDestination(
icon: Icon(Icons.person),
label: 'Profile',
),
NavigationDestination(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
)
28. Common Mistakes with Named Routes
Mistake 1: Route Name Typo
Navigator.pushNamed(context, '/profle');
If the registered route is /profile, the typo can cause route resolution problems.
Mistake 2: Forgetting to Register a Route
Navigator.pushNamed(context, '/settings');
But if /settings is not defined in the route configuration and no suitable route-generation handler exists, the route cannot be resolved.
Mistake 3: Incorrect Argument Type
final user = ModalRoute.of(context)!.settings.arguments as User;
If a different object type is passed, the cast can fail at runtime.
Mistake 4: Using Named Routes for Complex Routing Without Considering Their Limitations
For applications requiring sophisticated deep linking, browser history behavior, nested navigation, or complex route configuration, consider a Router-based approach or a routing package.
29. Best Practices
- Use meaningful route names such as
/profile and /settings.
- Keep route names consistent throughout the application.
- Consider using constants instead of repeatedly typing route strings.
- Use custom objects instead of large unstructured Maps when passing complex data.
- Validate route arguments before using them.
- Use
pushReplacementNamed() when the previous screen should not remain in the navigation stack.
- Use
pushNamedAndRemoveUntil() when an entire navigation history needs to be cleared.
- Use
onGenerateRoute when dynamic route creation is needed.
- Use
onUnknownRoute for a fallback destination where appropriate.
- For new applications with complex navigation requirements, evaluate modern routing solutions such as
go_router.
30. Quick Revision
| Concept | Code | Purpose |
| Define route | routes: {} | Register named routes |
| Start route | initialRoute | Choose initial named route |
| Open route | pushNamed() | Open a named screen |
| Close route | pop() | Return to previous screen |
| Pass data | arguments: | Send data to destination |
| Read data | ModalRoute.of() | Access route arguments |
| Dynamic routing | onGenerateRoute | Create routes dynamically |
| Fallback | onUnknownRoute | Handle unresolved routes |
| Replace route | pushReplacementNamed() | Replace current route |
| Clear stack | pushNamedAndRemoveUntil() | Remove previous routes |
| Pop and push | popAndPushNamed() | Replace current route with named route |
31. Interview Questions
Q1. What are named routes in Flutter?
Named routes are routes identified by string names and registered in the application's navigation configuration.
Q2. Which method is used to open a named route?
Navigator.pushNamed().
Q3. How do you close the current screen?
Use Navigator.pop(context).
Q4. How do you define named routes?
They can be registered using the routes property of MaterialApp or generated dynamically with route-generation callbacks.
Q5. How can data be passed to a named route?
Use the arguments parameter of Navigator.pushNamed().
Q6. How can named route arguments be accessed?
They can be accessed using ModalRoute.of(context)!.settings.arguments or handled inside onGenerateRoute.
Q7. What is the difference between pushNamed and pushReplacementNamed?
pushNamed() adds a new route to the navigation stack, while pushReplacementNamed() replaces the current route with the new named route.
Q8. What is onGenerateRoute?
onGenerateRoute is a callback that can dynamically create a route based on route settings such as the requested route name and arguments.
Q9. Are named routes recommended for all new Flutter applications?
No. Flutter's current documentation says named routes are no longer recommended for most applications. For simple navigation, Navigator with MaterialPageRoute can be used, while more advanced applications can use a routing package such as go_router.
32. Practice Exercise
Create a Flutter application with the following named routes:
/ → Home Screen
/login → Login Screen
/register → Register Screen
/dashboard → Dashboard Screen
/profile → Profile Screen
/settings → Settings Screen
Implement the following navigation flow:
Login
↓
Dashboard
↓
Profile
↓
Settings
Also practice:
- Passing a username to the Profile screen.
- Replacing Login with Dashboard after successful login.
- Returning from Profile to Dashboard.
- Clearing the navigation stack after logout.
- Creating an unknown-route fallback screen.
33. Key Takeaways
- Named routes provide string-based navigation between Flutter screens.
- Routes can be registered using the
routes property of MaterialApp.
Navigator.pushNamed() opens a named route.
Navigator.pop() closes the current route.
initialRoute can specify the starting named route.
- The
arguments parameter can be used to pass data.
ModalRoute.of(context) can retrieve route arguments.
onGenerateRoute supports dynamic route creation.
pushReplacementNamed() is useful for flows such as login to dashboard.
pushNamedAndRemoveUntil() can clear previous routes.
- Named routes are useful for learning and existing applications, but Flutter currently recommends other approaches for most new applications.
- For advanced navigation and deep linking, consider Router-based navigation or
go_router.
34. Official Flutter Resources
35. Learn Flutter with JustAcademy
To learn Flutter development, Dart programming, widgets, navigation, state management, APIs, Firebase integration, and practical application development, explore the following resources:
JustAcademy Flutter Training Course
Register for Flutter Course Demo